package com.qingfeng.music.api;

import com.shuji.android.library.BaseApplication;
import com.shuji.android.library.utils.NetWorkUtils;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.concurrent.TimeUnit;

import okhttp3.Cache;
import okhttp3.CacheControl;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;

/**
 * 利用 OkHTTP api 调用封装
 * <p>
 * ***********************缓存设置********************
 * <p>
 * 1. noCache 不使用缓存，全部走网络
 * <p>
 * 2. noStore 不使用缓存，也不存储缓存
 * <p>
 * 3. onlyIfCached 只使用缓存
 * <p>
 * 4. maxAge 设置最大失效时间，失效则不使用 需要服务器配合
 * <p>
 * 5. maxStale 设置最大失效时间，失效则不使用 需要服务器配合 感觉这两个类似 还没怎么弄清楚，清楚的同学欢迎留言
 * <p>
 * 6. minFresh 设置有效时间，依旧如上
 * <p>
 * 7. FORCE_NETWORK 只走网络
 * <p>
 * 8. FORCE_CACHE 只走缓存
 * <p>
 * <p>
 * Created by Ganlin.Wu on 2016/10/20.
 */
public class Api<T> {

    public static final int READ_TIME_OUT = 8000;//读超时长，单位：毫秒
    public static final int CONNECT_TIME_OUT = 8000; //连接时长，单位：毫秒

    /**
     * 设缓存有效期为两天
     */
    private static final long CACHE_STALE_SEC = 60 * 60 * 24 * 2;

    /**
     * 查询缓存的Cache-Control设置，为if-only-cache时只查询缓存而不会请求服务器，max-stale可以配合设置缓存失效时间
     * max-stale 指示客户机可以接收超出超时期间的响应消息。如果指定max-stale消息的值，那么客户机可接收超出超时期指定值之内的响应消息。
     */
    private static final String CACHE_CONTROL_CACHE = "only-if-cached, max-stale=" + CACHE_STALE_SEC;


    /**
     * 查询网络的Cache-Control设置，头部Cache-Control设为max-age=0
     * (假如请求了服务器并在a时刻返回响应结果，则在max-age规定的秒数内，浏览器将不会发送对应的请求到服务器，数据由缓存直接返回)时则不会使用缓存而请求服务器
     */
    private static final String CACHE_CONTROL_AGE = "max-age=0";

    private T mApiService;

    public T getApiService() {
        return mApiService;
    }


    /**
     * @param host
     */
    public Api(String host) {
        File cacheFile = new File(BaseApplication.getAppContext().getCacheDir(), "cache");//缓存
        Cache cache = new Cache(cacheFile, 1024 * 1024 * 100); //100Mb


        HttpLoggingInterceptor logInterceptor = new HttpLoggingInterceptor();//开启Log
        logInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);


        //header信息拦截器
        Interceptor headerInterceptor = new Interceptor() {
            @Override
            public Response intercept(Chain chain) throws IOException {//增加头部信息
                Request build = chain.request().newBuilder()
                        .addHeader("Content-Type", "application/json")
                        .header("User-Agent", "OkHttp Headers.java")
                        .addHeader("Accept", "application/json; q=0.5")
                        .addHeader("Accept", "application/vnd.github.v3+json")
                        .build();
                return chain.proceed(build);
            }
        };

        //实例化OkHttp
        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .readTimeout(READ_TIME_OUT, TimeUnit.MILLISECONDS)
                .connectTimeout(CONNECT_TIME_OUT, TimeUnit.MILLISECONDS)

                .addInterceptor(mRewriteCacheControlInterceptor)
                .addNetworkInterceptor(mRewriteCacheControlInterceptor)

                .addInterceptor(headerInterceptor)
                .addInterceptor(logInterceptor)

                .cache(cache)
                .build();

        //整合gson和RxJava
        Retrofit retrofit = new Retrofit.Builder()
                .client(okHttpClient)
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .baseUrl(host)
                .build();


        Type type = getClass().getGenericSuperclass();
        if (type instanceof ParameterizedType) {
            Class<T> cls = (Class<T>) ((ParameterizedType) type).getActualTypeArguments()[0];
            mApiService = retrofit.create(cls);
        }

    }


    /**
     * 云端响应头拦截器，用来配置缓存策略
     * <p>
     * Dangerous interceptor that rewrites the server's cache-control header.
     */
    private final Interceptor mRewriteCacheControlInterceptor = new Interceptor() {
        @Override
        public Response intercept(Chain chain) throws IOException {
            Request request = chain.request();

            if (!NetWorkUtils.isNetConnected(BaseApplication.getAppContext())) {
                request = request.newBuilder().cacheControl(CacheControl.FORCE_CACHE).build();
            }


            Response originalResponse = chain.proceed(request);
            if (NetWorkUtils.isNetConnected(BaseApplication.getAppContext())) {
                String cacheControl = request.cacheControl().toString();//有网的时候读接口上的@Headers里的配置，你可以在这里进行统一的设置
                return originalResponse.newBuilder().header("Cache-Control", cacheControl).removeHeader("Pragma").build();
            } else {
                return originalResponse.newBuilder().header("Cache-Control", "public, onlyIfCached, max-stale=" + CACHE_STALE_SEC).removeHeader("Pragma").build();
            }
        }
    };

}
